classdef ClassifierChains ...
        < MultiLabelAlgorithm ...
        & BinaryClassAlgorithm0able ...
        & ZAlgorithmable ...
        & MultiLabelMetricable
    %CLASSIFIERCHAINS Summary of this class goes here
    %   Detailed explanation goes here
    
    properties
    end
    
    methods
        function [ this ] =  ClassifierChains( name, algorithm0 )
            if nargin == 0
                this.setName('cc');
            end
            if nargin >= 1
                this.setName(name);
            end
            if nargin >= 2
                this.setAlgorithm0(algorithm0);
            end
        end
    end
    
    methods
        function [  ] = build( this, X1, Y1 )
            %BUILD Summary of this function goes here
            %   Detailed explanation goes here
            % ClassifierChains::
            
            nLabel = size(Y1, 2);
            this.zAlgorithm = cell(1, nLabel);
            
            X1_aug_i = X1; % X1 augmented
            for iLabel = 1:nLabel
                %     X1_aug_i = [X1, Y1(:, 1:(iLabel - 1))];
                Y1_i = Y1(:, iLabel);
                
                this.zAlgorithm{iLabel} = this.algorithm0.clone();
                this.zAlgorithm{iLabel}.build(X1_aug_i, Y1_i);
                
                X1_aug_i = [X1_aug_i, Y1_i];
            end
        end
        
        function [ result ] = apply( this, X2, Y2 )
            %APPLY Summary of this function goes here
            %   Detailed explanation goes here
            % ClassifierChains::
            
            nLabel = size(Y2, 2);
            
            result.Y_hat = zeros(size(Y2));
            result.Y_out = result.Y_hat;
            
            X2_aug_i = X2;
            for iLabel = 1:nLabel
                Y2_i = Y2(:, iLabel);
                
                result_i = this.zAlgorithm{iLabel}.apply(X2_aug_i, Y2_i);
                
                result.Y_hat(:, iLabel) = result_i.Y_hat;
                result.Y_out(:, iLabel) = result_i.Y_out;
                
                X2_aug_i = [X2_aug_i, result_i.Y_hat];
            end
        end
    end
    
end

